Skip to content

add some changes#64

Open
afuhflynn wants to merge 1 commit intomainfrom
feat/settings-upgrade
Open

add some changes#64
afuhflynn wants to merge 1 commit intomainfrom
feat/settings-upgrade

Conversation

@afuhflynn
Copy link
Copy Markdown
Owner

@afuhflynn afuhflynn commented Jan 5, 2026

Summary by CodeRabbit

  • New Features

    • Added theme synchronization for appearance settings
    • Expanded settings tabs with new account and security options
  • Bug Fixes

    • Prevented accidental revocation of the currently active session
    • Improved GitHub profile URL fallback handling
  • UI Improvements

    • Enhanced border styling across settings interface components

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

This PR refactors session management authentication, adds username to profile API responses, synchronizes theming with next-themes in the settings UI, moves SettingsTab to a centralized type definition, and applies border styling updates across UI primitives.

Changes

Cohort / File(s) Summary
Session Management & Authentication
app/api/settings/sessions/route.ts, app/api/settings/sessions/[sessionId]/route.ts
Replaces requireAuth with explicit auth.api.getSession calls; adds 401 responses on missing sessions. DELETE method now uses async params and compound where clause (id + userId). Adds session token comparison to prevent revoking active session; returns 400 if attempted.
Profile API & Response Shape
app/api/settings/profile/route.ts
Adds username field to user object in GET response via Prisma select. Removes trailing commas in error responses.
Settings UI Layer
components/settings/settings-content.tsx, components/settings/settings-sidebar.tsx
Removes billing hooks from settings-content. Adds theme synchronization via next-themes. Changes activeSection prop type from string to SettingsTab. Introduces optional chaining for profile/AI data access. Updates session display logic. Applies dynamic className via cn utility in sidebar. Removes SettingsTab type alias from sidebar (moved to types.d.ts).
UI Primitives & Styling
components/ui/input.tsx, components/ui/switch.tsx, components/ui/textarea.tsx
Adds border-border! CSS class to input aria-invalid state, switch root/thumb, and textarea. Minor formatting: adds semicolons to imports/exports.
Type System & Client
types.d.ts, lib/api-client.ts, nuqs/index.ts
Adds UserProfile interface and SettingsTab union type to types.d.ts. Updates api.queries.settings.getProfile return type to Promise<UserProfile | null>. Expands searchParamsSchema.settings_tab enum to include "account", "secutiry", "repositories".
Settings Page Layer
app/(dashboard)/settings/page.tsx
Adds @ts-ignore pragmas before passing activeSection props and setActiveSection handler to suppress TypeScript errors; no runtime logic changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 Session tokens now checked with care,
Auth flows strengthened everywhere,
Types declared where they belong,
Themes sync'd all day long,
Borders gleaming, borders bright—
Settings UI shines just right!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'add some changes' is vague and generic, using non-descriptive language that doesn't convey meaningful information about the extensive settings system overhaul, authentication refactoring, and UI styling updates in this changeset. Use a more descriptive title that captures the primary change, such as 'Refactor settings API authentication and add profile type definitions' or 'Upgrade settings system with improved auth handling and UI styling'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codereverb
Copy link
Copy Markdown

codereverb bot commented Jan 5, 2026

Summary by CodeReverb

  • Refactored session management in API routes (/api/settings/sessions) to use auth.api.getSession, adding explicit unauthorized checks, preventing current session revocation, and implementing actual session deletion via Prisma.
  • Expanded settings page functionality by introducing new tabs (account, security, repositories), integrating username into profile settings, and applying theme changes via next-themes.
  • Applied consistent border-border! styling to various UI components (Input, Textarea, Switch) and notification sections for a unified look.
  • Removed billing-related hooks (useSettingsBilling, useUpdateSettingsBilling) from SettingsContent, indicating a refactoring or removal of billing functionality from this section.

Generated automatically by CodeReverb Try out CodeReverb

@codereverb
Copy link
Copy Markdown

codereverb bot commented Jan 5, 2026

Code review by CodeReverb

Summary

This pull request introduces significant changes to the settings pages and their associated API routes, primarily focusing on session management and profile updates. It also includes type definition enhancements and minor UI styling adjustments.

  • Key Changes: Refactored session API routes for improved security and functionality, added username to profile data, introduced new SettingsTab types, and applied styling overrides.
  • Risk Level: Medium, due to changes in authentication/session management logic and type safety bypasses.
  • Main Affected Area(s): User settings (profile, sessions, appearance), API authentication.

Changes (per file)

File: app/(dashboard)/settings/page.tsx

  • Purpose: Renders the main settings page, orchestrating the sidebar and content components.
  • Key modifications:
    • Line(s): 26, 28, 35 — Added @ts-ignore directives to bypass TypeScript errors for activeSection and setActiveSection props passed to SettingsSidebar and SettingsContent.
  • Impact: Introduces type safety holes, potentially masking underlying type mismatches between the page and its child components.
  • Confidence: HIGH — The @ts-ignore comments are explicit.

File: app/api/settings/profile/route.ts

  • Purpose: Handles API requests for user profile data.
  • Key modifications:
    • Line(s): 22 — Added username: true to the Prisma select statement for the GET request, ensuring the username is fetched.
    • Line(s): 35, 75 — Minor formatting change, removing trailing commas from NextResponse.json options.
  • Impact: The profile API will now return the user's username. Minimal impact otherwise.
  • Confidence: HIGH.

File: app/api/settings/sessions/[sessionId]/route.ts

  • Purpose: Handles API requests for revoking a specific user session.
  • Key modifications:
    • Line(s): 3, 4, 5 — Replaced requireAuth with auth from @/lib/auth and imported headers and prisma.
    • Line(s): 9 — Changed the type of params from { sessionId: string } to Promise<{ sessionId: string }>.
    • Line(s): 12-37 — Rewrote the session revocation logic to use auth.api.getSession, explicitly check for unauthorized access, prevent revoking the current session, and perform actual session deletion via Prisma.
  • Impact: Significant security and functional changes to session revocation. The params type change is highly suspicious and likely incorrect.
  • Confidence: HIGH (visible code changes).

File: app/api/settings/sessions/route.ts

  • Purpose: Handles API requests for listing and revoking all user sessions.
  • Key modifications:
    • Line(s): 3, 4, 5 — Replaced requireAuth with auth from @/lib/auth and imported headers.
    • Line(s): 60-66, 84-90 — Rewrote authentication for GET and DELETE endpoints to use auth.api.getSession and added explicit unauthorized checks.
    • Line(s): 68, 91 — Changed currentToken retrieval from request.cookies.get("session")?.value to session.session.token.
  • Impact: Improved security and consistency in session management API authentication.
  • Confidence: HIGH.

File: components/settings/settings-content.tsx

  • Purpose: Renders the main content area for various settings sections.
  • Key modifications:
    • Line(s): 15 — Changed activeSection prop type from string to SettingsTab.
    • Line(s): 20, 21 — Removed useSettingsBilling and useUpdateSettingsBilling hooks.
    • Line(s): 23 — Added useTheme hook from next-themes.
    • Line(s): 257, 324 — Modified githubUrl initialization to default to https://github.com/${profile.username} if profile.githubUrl is empty.
    • Line(s): 359 — Added setTheme(appearanceSettings?.theme) to apply the theme on load.
    • Line(s): 760-766 — Changed session.lastActive display logic to directly show session.lastActive instead of calculating "X hours ago".
    • Line(s): 389, 411, 421, 438, 456, 468, 482, 811, 832, 850, 868, 894, 912 — Added border-border! to className attributes of various UI elements (CardContent, Input, Switch).
    • Line(s): 973 — Added optional chaining ? to aiSettingsData?.maxTokens?.toString().
    • Line(s): 1135 — Added setTheme(value) to update the theme when appearance settings change.
  • Impact: Improved type safety for activeSection (though bypassed in parent), removal of billing features (INSUFFICIENT CONTEXT if intended), theme integration, more robust githubUrl default, potential regression in lastActive display if session.lastActive is not a pre-formatted string, and widespread styling overrides.
  • Confidence: HIGH.

File: components/settings/settings-sidebar.tsx

  • Purpose: Renders the navigation sidebar for settings sections.
  • Key modifications:
    • Line(s): 6 — Imported cn utility.
    • Line(s): 88-95 — Removed local SettingsTab type definition.
    • Line(s): 143, 170, 197 — Added cn utility to Button components to conditionally apply text-accent-foreground! bg-accent! classes when a section is active.
  • Impact: Styling change for active sidebar items, type definition moved to types.d.ts.
  • Confidence: HIGH.

File: components/ui/input.tsx

  • Purpose: Defines a reusable Input component.
  • Key modifications:
    • Line(s): 12 — Added border-border! to the className string.
  • Impact: Overrides the default border style for all Input components.
  • Confidence: HIGH.

File: components/ui/switch.tsx

  • Purpose: Defines a reusable Switch component.
  • Key modifications:
    • Line(s): 14 — Added border-border! to the className string for the switch root.
    • Line(s): 21 — Added border-border! to the className string for the switch thumb.
  • Impact: Overrides the default border style for all Switch components.
  • Confidence: HIGH.

File: components/ui/textarea.tsx

  • Purpose: Defines a reusable Textarea component.
  • Key modifications:
    • Line(s): 10 — Added border-border! to the className string.
  • Impact: Overrides the default border style for all Textarea components.
  • Confidence: HIGH.

File: lib/api-client.ts

  • Purpose: Provides a client for interacting with the application's API.
  • Key modifications:
    • Line(s): 66 — Updated the return type of getProfile to Promise<UserProfile | null>.
  • Impact: Improves type safety for API client calls to the profile endpoint.
  • Confidence: HIGH.

File: nuqs/index.ts

  • Purpose: Defines query parameter schemas using nuqs.
  • Key modifications:
    • Line(s): 21, 22, 23 — Added new enum values (account, security, repositories) to the settings_tab parser.
  • Impact: Extends the set of valid values for the settings_tab URL query parameter.
  • Confidence: HIGH.

File: types.d.ts

  • Purpose: Centralized type definitions for the application.
  • Key modifications:
    • Line(s): 29-40 — Added UserProfile interface.
    • Line(s): 42-52 — Added SettingsTab type definition, including new values (account, security, repositories).
  • Impact: Improves type safety and consistency across the codebase by providing explicit types for user profiles and settings tabs.
  • Confidence: HIGH.

Critical Issues

  • Severity: HIGH

  • Confidence: HIGH

  • Location: app/(dashboard)/settings/page.tsx:26-28, 35

  • Issue: Type safety bypassed with @ts-ignore.

  • Evidence:

    --- a/app/(dashboard)/settings/page.tsx
    +++ b/app/(dashboard)/settings/page.tsx
    @@ -24,8 +24,10 @@ export default function SettingsPage() {
              {/* Settings Navigation Sidebar */}
              <div className="lg:col-span-1">
                <SettingsSidebar
    +              // @ts-ignore
                  activeSection={params.settings_tab}
                  setActiveSection={(v) =>
    +                // @ts-ignore
                    setParams({ ...params, settings_tab: v })
                  }
                />
    @@ -34,6 +36,7 @@ export default function SettingsPage() {
              {/* Main Content Area */}
              <div className="lg:col-span-3">
                <SettingsContent
    +              // @ts-ignore
                  activeSection={params.settings_tab}
                  hasChanges={hasChanges}
                  setHasChanges={setHasChanges}
  • Analysis:

    • The use of @ts-ignore indicates a type mismatch that is being suppressed rather than resolved.
    • SettingsContent and SettingsSidebar now expect activeSection to be of type SettingsTab (as per components/settings/settings-content.tsx and types.d.ts), but params.settings_tab might not be correctly typed or validated.
    • This bypasses compile-time checks, potentially leading to runtime errors if params.settings_tab receives an unexpected value.
  • Suggested fix:

    • Ensure params.settings_tab is correctly typed as SettingsTab (e.g., by using a parser from nuqs that validates against SettingsTab or by casting it safely after validation). Remove @ts-ignore.
  • Severity: HIGH

  • Confidence: HIGH

  • Location: app/api/settings/sessions/[sessionId]/route.ts:9

  • Issue: Incorrect type for params in Next.js API route.

  • Evidence:

    --- a/app/api/settings/sessions/[sessionId]/route.ts
    +++ b/app/api/settings/sessions/[sessionId]/route.ts
    @@ -1,22 +1,48 @@
    import { NextRequest, NextResponse } from "next/server";
    -import { requireAuth } from "@/lib/auth-utils";
    +import { auth } from "@/lib/auth";
    +import { headers } from "next/headers";
    +import { prisma } from "@/lib/prisma";
    
    export async function DELETE(
      request: NextRequest,
    -  { params }: { params: { sessionId: string } },
    +  { params }: { params: Promise<{ sessionId: string }> }
     ) {
  • Analysis:

    • Next.js dynamic route params are typically plain objects, not Promises.
    • Attempting to await params will likely result in a runtime error or unexpected behavior, as params is already the resolved object containing sessionId.
  • Suggested fix:

    • Change the type back to { params: { sessionId: string } } and access sessionId directly:
      export async function DELETE(
        request: NextRequest,
        { params }: { params: { sessionId: string } }
      ) {
        try {
          // ...
          const { sessionId } = params; // Access directly
          // ...
        }
      }
  • Severity: MEDIUM

  • Confidence: LOW

  • Location: components/settings/settings-content.tsx:20-21

  • Issue: Removal of billing hooks without clear context.

  • Evidence:

    --- a/components/settings/settings-content.tsx
    +++ b/components/settings/settings-content.tsx
    @@ -56,8 +56,6 @@ import {
     useDisable2FA,
     useRevokeSession,
     useRevokeAllSessions,
    -  useSettingsBilling,
    -  useUpdateSettingsBilling,
     useSettingsRepositories,
     useDisconnectRepository,
     useDisconnectAllRepositories,
  • Analysis:

    • The useSettingsBilling and useUpdateSettingsBilling hooks have been removed.
    • INSUFFICIENT CONTEXT: It's unclear if billing functionality is being deprecated, moved to another component, or if this is an accidental removal. If billing is still a feature, this is a functional regression.
  • Suggested fix:

    • Confirm if billing functionality is intentionally removed. If not, restore the hooks and associated UI. If so, ensure all related code (e.g., API routes, UI components) is also removed or updated accordingly.
  • Severity: MEDIUM

  • Confidence: LOW

  • Location: components/settings/settings-content.tsx:760-766

  • Issue: Potential regression in session lastActive display.

  • Evidence:

    --- a/components/settings/settings-content.tsx
    +++ b/components/settings/settings-content.tsx
    @@ -759,13 +759,7 @@ export function SettingsContent({
                     <p className="font-medium">{session.device}</p>
                     <p className="text-sm text-muted-foreground">
                       {session.location} •{" "}
    -                  {session.current
    -                      ? "Active now"
    -                      : `${Math.floor(
    -                          (Date.now() -
    -                            new Date(session.lastActive).getTime()) /
    -                            (1000 * 60 * 60)
    -                        )} hours ago`}
    +                  {session.current ? "Active now" : session.lastActive}
                     </p>
                   </div>
                   {session.current ? (
  • Analysis:

    • The previous code calculated "X hours ago" from session.lastActive. The new code directly displays session.lastActive.
    • INSUFFICIENT CONTEXT: If session.lastActive is now a pre-formatted string (e.g., "2 hours ago", "Yesterday"), this change is fine. However, if it's still a Date object, displaying it directly will show an unformatted date string, which is a regression in user experience.
  • Suggested fix:

    • Confirm the type and format of session.lastActive. If it's a Date object, re-implement the formatting or ensure the API provides a pre-formatted string.

Suggestions

  • Type: quality

  • Confidence: HIGH

  • Action: Add a descriptive pull request description.

  • Why: A clear description helps reviewers understand the intent and scope of changes, especially for a PR with multiple significant modifications.

  • Type: style

  • Confidence: HIGH

  • Action: Review the use of border-border! across UI components.

  • Why: While border-border! explicitly sets a border, ensure this is the intended global override and doesn't lead to unexpected styling regressions or inconsistencies with existing theming/utility classes. Consider if a more targeted approach or a theme configuration change would be more appropriate.


Tests & Verification

  • Tests added/modified? no
  • Recommended tests:
    • Session API (/api/settings/sessions and /[sessionId]):
      • Verify a user can fetch their sessions.
      • Verify a user can revoke a specific session (not the current one).
      • Verify a user cannot revoke their current active session.
      • Verify an unauthenticated user cannot access session endpoints.
      • Verify a user cannot revoke another user's session (if applicable).
    • Profile API (/api/settings/profile):
      • Verify the username field is returned in the GET response.
    • Settings UI (app/(dashboard)/settings/page.tsx, SettingsContent, SettingsSidebar):
      • Verify navigation between settings tabs works correctly.
      • Verify the active tab styling is applied correctly in the sidebar.
      • Verify the githubUrl field correctly defaults to github.com/username when empty.
      • Verify the session.lastActive display is user-friendly and correctly formatted.
      • Verify the theme changes correctly when selected in appearance settings.
  • Confidence: HIGH.

Pre-merge Checklist

  • All HIGH severity issues addressed or explicitly accepted.
  • Appropriate unit tests exist or are added for changed logic.
  • Risky paths (auth, payments, persistence, concurrency) manually reviewed. (Auth and persistence reviewed in this CR)
  • CI/test suite passes.

Review Confidence Summary

  • High confidence: The @ts-ignore directives are clear issues. The params: Promise<{ sessionId: string }> type in the API route is a definite bug. The changes to session management API routes are significant and correctly identified.
  • Medium/low confidence: The impact of removing billing hooks and the correct formatting of session.lastActive depend on external context not provided in the diff.
  • Items requiring manual review:
    1. Resolution of @ts-ignore in app/(dashboard)/settings/page.tsx.
    2. Correction of params type in app/api/settings/sessions/[sessionId]/route.ts.
    3. Confirmation of billing feature status after hook removal.
    4. Verification of session.lastActive display format.
    5. Thorough testing of all session management API endpoints (list, revoke single, revoke all) for security and correctness.
    6. Visual regression testing for all UI components affected by border-border! styling.

End of Review
This review followed the Anti-Hallucination Protocol: only visible diff analyzed; assumptions labeled; speculative items minimized.


Powered by CodeReverb Try out CodeReverb

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Fix all issues with AI Agents 🤖
In @app/(dashboard)/settings/page.tsx:
- Around line 27-31: The current @ts-ignore hides a type mismatch between
params.settings_tab and the SettingsSidebar/SettingsContent props; fix by
aligning types instead of ignoring: update your nuqs schema to parse
settings_tab as the SettingsTab enum (e.g., in nuqs/index.ts use
parseAsStringEnum<SettingsTab>(...) with a default) so params.settings_tab is
typed correctly, or at the usage site replace the @ts-ignore with an explicit
assertion activeSection={params.settings_tab as SettingsTab}; remove the
@ts-ignore lines and ensure both SettingsSidebar and SettingsContent accept
SettingsTab typed values.

In @app/api/settings/sessions/[sessionId]/route.ts:
- Around line 21-31: Check that prisma.session.findUnique returns a session and
that it belongs to the authenticated user before proceeding: modify the
findUnique call (symbol: prisma.session.findUnique) to include userId:
session.user.id in the where clause, then if sessionToRevoke is null return
NextResponse.json({ error: "Session not found" }, { status: 404 }); only after
that compare sessionToRevoke.token with currentToken and proceed with deletion;
ensure you reference sessionToRevoke and currentToken exactly as in the diff.

In @components/settings/settings-content.tsx:
- Around line 326-327: The githubUrl fallback builds
`https://github.com/${profile.username}` without guarding against an undefined
`profile.username`; update the `githubUrl` assignment (the `githubUrl` property
where `profile?.githubUrl || \`https://github.com/${profile.username}\` || ""`
is used) to only construct the URL when `profile?.username` exists (e.g. use a
conditional or nullish-coalescing: `profile?.githubUrl ?? (profile?.username ?
\`https://github.com/${profile.username}\` : "")`) so you don't interpolate
`undefined` into the URL.
- Around line 358-363: The useEffect should guard against
appearanceSettings.theme being undefined and include setTheme in the dependency
array; inside the effect call setAppearanceData(appearanceSettings) as before
but only call setTheme with a defined value (e.g., appearanceSettings.theme ??
<defaultTheme>) or check if appearanceSettings.theme !== undefined before
calling setTheme, and add setTheme to the dependency array so the effect reads:
useEffect(() => { if (appearanceSettings) {
setAppearanceData(appearanceSettings); if (appearanceSettings.theme !==
undefined) setTheme(appearanceSettings.theme); } }, [appearanceSettings,
setTheme]);
- Around line 258-259: The githubUrl assignment (githubUrl in
settings-content.tsx) currently uses profile?.githubUrl ||
`https://github.com/${profile.username}` || "" which is redundant and can
produce "https://github.com/undefined"; change it to prefer profile?.githubUrl,
then only build the template URL if profile?.username is present, otherwise fall
back to an empty string (e.g., use nullish/conditional logic so the template
literal is only used when profile.username exists).

In @nuqs/index.ts:
- Around line 21-23: Fix the typo in the settings tab list: replace the
misspelled string "secutiry" with "security" in the exported tab
enumeration/array defined in index.ts (the array containing "account",
"secutiry", "repositories") so URL param ?settings_tab=security will match.
Ensure the corrected string is used wherever that exported list (settings tabs
enum/array) is referenced for routing or URL parsing.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/api/settings/sessions/route.ts (1)

119-140: Missing existence check for the session to revoke.

If sessionId refers to a non-existent session, sessionToRevoke will be null. The optional chaining at line 126 will evaluate to undefined !== currentToken, passing the check. The subsequent prisma.session.delete will throw an error for a non-existent record, resulting in a generic 500 error instead of a proper 404.

🔎 Proposed fix
       const sessionToRevoke = await prisma.session.findUnique({
         where: { id: sessionId },
       });

+      if (!sessionToRevoke) {
+        return NextResponse.json(
+          { error: "Session not found" },
+          { status: 404 }
+        );
+      }
+
       // Prevent revoking current session
-      if (sessionToRevoke?.token === currentToken) {
+      if (sessionToRevoke.token === currentToken) {
         return NextResponse.json(
           { error: "Cannot revoke current session" },
           { status: 400 }
         );
       }
app/api/settings/profile/route.ts (1)

56-67: Inconsistent response shape: PUT handler missing username field.

The GET handler now returns username (line 22), but the PUT handler's select statement doesn't include it. This creates inconsistent response shapes between GET and PUT, which could break frontend code expecting a uniform UserProfile type.

🔎 Proposed fix to include username in PUT response
      select: {
        id: true,
        name: true,
        email: true,
        bio: true,
        location: true,
        website: true,
        githubUrl: true,
        image: true,
        showEmail: true,
        showLocation: true,
+       username: true,
      },
🧹 Nitpick comments (2)
app/api/settings/sessions/route.ts (1)

1-6: Remove unused import requireAuth.

The requireAuth import on line 2 is no longer used after refactoring to auth.api.getSession. This is dead code.

🔎 Proposed fix
 import { NextRequest, NextResponse } from "next/server";
-import { requireAuth } from "@/lib/auth-utils";
 import { prisma } from "@/lib/prisma";
 import { UAParser } from "ua-parser-js";
 import { auth } from "@/lib/auth";
 import { headers } from "next/headers";
components/settings/settings-sidebar.tsx (1)

144-149: Consider consolidating active state styling.

The active state is handled in two places: via variant prop and via className with !important overrides. This duplication can lead to maintenance issues.

If the secondary variant doesn't provide the desired styling, consider either:

  1. Customizing the button variant in your design system, or
  2. Removing the variant logic and relying solely on cn() classes.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 013e772 and 0608c9d.

📒 Files selected for processing (12)
  • app/(dashboard)/settings/page.tsx
  • app/api/settings/profile/route.ts
  • app/api/settings/sessions/[sessionId]/route.ts
  • app/api/settings/sessions/route.ts
  • components/settings/settings-content.tsx
  • components/settings/settings-sidebar.tsx
  • components/ui/input.tsx
  • components/ui/switch.tsx
  • components/ui/textarea.tsx
  • lib/api-client.ts
  • nuqs/index.ts
  • types.d.ts
🧰 Additional context used
🧬 Code graph analysis (5)
app/api/settings/sessions/route.ts (1)
lib/auth.ts (1)
  • auth (6-24)
components/ui/textarea.tsx (1)
lib/utils.ts (1)
  • cn (4-6)
components/settings/settings-content.tsx (3)
components/ui/card.tsx (1)
  • CardContent (91-91)
components/ui/dialog.tsx (3)
  • DialogDescription (136-136)
  • DialogHeader (138-138)
  • DialogFooter (137-137)
components/ui/button.tsx (1)
  • Button (59-59)
app/api/settings/sessions/[sessionId]/route.ts (2)
app/api/settings/sessions/route.ts (1)
  • DELETE (104-161)
lib/auth.ts (1)
  • auth (6-24)
components/ui/switch.tsx (1)
lib/utils.ts (1)
  • cn (4-6)
🔇 Additional comments (15)
app/api/settings/sessions/route.ts (2)

62-72: LGTM!

The refactored authentication using auth.api.getSession with proper 401 handling is correct and follows a consistent pattern.


104-114: LGTM!

The DELETE handler's authentication refactoring is consistent with the GET handler and properly returns 401 for unauthorized requests.

app/api/settings/sessions/[sessionId]/route.ts (2)

6-8: LGTM!

The params type correctly uses Promise<{ sessionId: string }> which is required for Next.js 15+ async route parameters.


11-18: LGTM!

Consistent authentication pattern with proper 401 handling.

app/api/settings/profile/route.ts (1)

22-22: LGTM! Username field added to profile response.

The addition of the username field aligns with the new UserProfile type definition and enriches the profile API response.

components/ui/switch.tsx (1)

16-16: LGTM! Consistent border styling applied.

The border-border! class additions align with the broader UI styling updates across components, ensuring consistent border theming.

Also applies to: 24-24

types.d.ts (2)

31-42: LGTM! Well-structured UserProfile interface.

The UserProfile interface correctly captures all profile fields returned by the API, including the newly added username. The optional image field is appropriately typed.


44-53: LGTM! Type-safe settings navigation.

The SettingsTab union type provides compile-time safety for settings navigation and centralizes the valid tab values.

components/ui/textarea.tsx (1)

10-10: LGTM! Consistent border styling applied.

The border-border! class addition aligns with the UI-wide border theming updates.

components/ui/input.tsx (1)

13-13: LGTM! Consistent border styling applied.

The border-border! class addition maintains consistent border theming across input components, even though it's grouped with the aria-invalid classes for organization.

components/settings/settings-sidebar.tsx (1)

18-18: LGTM!

Good addition of the cn utility for conditional class merging.

components/settings/settings-content.tsx (3)

63-63: Good integration with next-themes.

The pattern of calling setTheme both on initial load (from server settings) and on user selection provides immediate visual feedback while persisting the preference.

Also applies to: 76-76, 1132-1132


971-971: Good defensive coding with optional chaining.

The aiSettingsData?.maxTokens?.toString() guards against undefined values during initial render before data loads.


66-66: LGTM — improved type safety.

Changing activeSection from string to SettingsTab provides better type checking and IDE support.

lib/api-client.ts (1)

67-68: Good improvement to type safety.

The explicit UserProfile return type is better than any. UserProfile is properly declared as a global ambient type in types.d.ts (lines 31-42), making it correctly accessible without explicit import in this file.

Comment on lines +27 to 31
// @ts-ignore
activeSection={params.settings_tab}
setActiveSection={(v) =>
// @ts-ignore
setParams({ ...params, settings_tab: v })
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Avoid @ts-ignore — fix the underlying type mismatch instead.

Using @ts-ignore suppresses TypeScript errors without resolving them, which defeats the purpose of having typed props. The mismatch likely stems from params.settings_tab being typed as string (from nuqs) while SettingsSidebar and SettingsContent expect SettingsTab.

Consider typing the nuqs schema to align with SettingsTab:

// In nuqs/index.ts, import and use SettingsTab for better type inference
settings_tab: parseAsStringEnum<SettingsTab>([...]).withDefault("profile")

Or cast at the usage site with a type assertion rather than ignoring:

activeSection={params.settings_tab as SettingsTab}

Also applies to: 39-40

🤖 Prompt for AI Agents
In @app/(dashboard)/settings/page.tsx around lines 27-31, The current @ts-ignore
hides a type mismatch between params.settings_tab and the
SettingsSidebar/SettingsContent props; fix by aligning types instead of
ignoring: update your nuqs schema to parse settings_tab as the SettingsTab enum
(e.g., in nuqs/index.ts use parseAsStringEnum<SettingsTab>(...) with a default)
so params.settings_tab is typed correctly, or at the usage site replace the
@ts-ignore with an explicit assertion activeSection={params.settings_tab as
SettingsTab}; remove the @ts-ignore lines and ensure both SettingsSidebar and
SettingsContent accept SettingsTab typed values.

Comment on lines +21 to +31
const sessionToRevoke = await prisma.session.findUnique({
where: { id: sessionId },
});

// Prevent revoking current session
if (sessionToRevoke?.token === currentToken) {
return NextResponse.json(
{ error: "Cannot revoke current session" },
{ status: 400 }
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing existence check for the session to revoke.

Same issue as in app/api/settings/sessions/route.ts: if the session doesn't exist, sessionToRevoke is null, and the code proceeds to attempt deletion which will throw, resulting in a 500 error instead of a proper 404.

Additionally, consider adding userId: session.user.id to the findUnique query to ensure the session belongs to the authenticated user before comparing tokens.

🔎 Proposed fix
     const { sessionId } = await params;
     const sessionToRevoke = await prisma.session.findUnique({
-      where: { id: sessionId },
+      where: { id: sessionId, userId: session.user.id },
     });

+    if (!sessionToRevoke) {
+      return NextResponse.json(
+        { error: "Session not found" },
+        { status: 404 }
+      );
+    }
+
     // Prevent revoking current session
-    if (sessionToRevoke?.token === currentToken) {
+    if (sessionToRevoke.token === currentToken) {
       return NextResponse.json(
         { error: "Cannot revoke current session" },
         { status: 400 }
       );
     }
-
-    await prisma.session.delete({
-      where: {
-        id: sessionId,
-        userId: session.user.id,
-      },
-    });
+
+    await prisma.session.delete({
+      where: { id: sessionId },
+    });

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @app/api/settings/sessions/[sessionId]/route.ts around lines 21-31, Check
that prisma.session.findUnique returns a session and that it belongs to the
authenticated user before proceeding: modify the findUnique call (symbol:
prisma.session.findUnique) to include userId: session.user.id in the where
clause, then if sessionToRevoke is null return NextResponse.json({ error:
"Session not found" }, { status: 404 }); only after that compare
sessionToRevoke.token with currentToken and proceed with deletion; ensure you
reference sessionToRevoke and currentToken exactly as in the diff.

Comment on lines +258 to +259
githubUrl:
profile?.githubUrl || `https://github.com/${profile.username}` || "",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Redundant fallback and potential "undefined" in URL.

The trailing || "" is unreachable since template literals always produce a string. Also, if profile.username is undefined/null, this produces "https://github.com/undefined".

🔎 Proposed fix
         githubUrl:
-          profile?.githubUrl || `https://github.com/${profile.username}` || "",
+          profile?.githubUrl || (profile.username ? `https://github.com/${profile.username}` : ""),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
githubUrl:
profile?.githubUrl || `https://github.com/${profile.username}` || "",
githubUrl:
profile?.githubUrl || (profile.username ? `https://github.com/${profile.username}` : ""),
🤖 Prompt for AI Agents
In @components/settings/settings-content.tsx around lines 258-259, The githubUrl
assignment (githubUrl in settings-content.tsx) currently uses profile?.githubUrl
|| `https://github.com/${profile.username}` || "" which is redundant and can
produce "https://github.com/undefined"; change it to prefer profile?.githubUrl,
then only build the template URL if profile?.username is present, otherwise fall
back to an empty string (e.g., use nullish/conditional logic so the template
literal is only used when profile.username exists).

Comment on lines +326 to +327
githubUrl:
profile?.githubUrl || `https://github.com/${profile.username}` || "",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same issue as line 258-259 — guard against undefined username.

🔎 Proposed fix
         githubUrl:
-          profile?.githubUrl || `https://github.com/${profile.username}` || "",
+          profile?.githubUrl || (profile.username ? `https://github.com/${profile.username}` : ""),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
githubUrl:
profile?.githubUrl || `https://github.com/${profile.username}` || "",
githubUrl:
profile?.githubUrl || (profile.username ? `https://github.com/${profile.username}` : ""),
🤖 Prompt for AI Agents
In @components/settings/settings-content.tsx around lines 326-327, The githubUrl
fallback builds `https://github.com/${profile.username}` without guarding
against an undefined `profile.username`; update the `githubUrl` assignment (the
`githubUrl` property where `profile?.githubUrl ||
\`https://github.com/${profile.username}\` || ""` is used) to only construct the
URL when `profile?.username` exists (e.g. use a conditional or
nullish-coalescing: `profile?.githubUrl ?? (profile?.username ?
\`https://github.com/${profile.username}\` : "")`) so you don't interpolate
`undefined` into the URL.

Comment on lines 358 to 363
useEffect(() => {
if (appearanceSettings) {
setAppearanceData(appearanceSettings);
setTheme(appearanceSettings?.theme);
}
}, [appearanceSettings]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against undefined theme value.

appearanceSettings?.theme could be undefined, which may cause unexpected behavior when passed to setTheme. Additionally, setTheme should be in the dependency array to satisfy exhaustive-deps (though it's stable).

🔎 Proposed fix
   useEffect(() => {
     if (appearanceSettings) {
       setAppearanceData(appearanceSettings);
-      setTheme(appearanceSettings?.theme);
+      if (appearanceSettings.theme) {
+        setTheme(appearanceSettings.theme);
+      }
     }
-  }, [appearanceSettings]);
+  }, [appearanceSettings, setTheme]);
🤖 Prompt for AI Agents
In @components/settings/settings-content.tsx around lines 358-363, The useEffect
should guard against appearanceSettings.theme being undefined and include
setTheme in the dependency array; inside the effect call
setAppearanceData(appearanceSettings) as before but only call setTheme with a
defined value (e.g., appearanceSettings.theme ?? <defaultTheme>) or check if
appearanceSettings.theme !== undefined before calling setTheme, and add setTheme
to the dependency array so the effect reads: useEffect(() => { if
(appearanceSettings) { setAppearanceData(appearanceSettings); if
(appearanceSettings.theme !== undefined) setTheme(appearanceSettings.theme); }
}, [appearanceSettings, setTheme]);

Comment on lines +21 to +23
"account",
"secutiry",
"repositories",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Typo: "secutiry" should be "security".

This typo will break URL-based navigation to the security tab — the URL param ?settings_tab=security won't match the misspelled enum value, causing fallback to the default "profile" tab.

🔎 Proposed fix
     "account",
-    "secutiry",
+    "security",
     "repositories",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"account",
"secutiry",
"repositories",
"account",
"security",
"repositories",
🤖 Prompt for AI Agents
In @nuqs/index.ts around lines 21-23, Fix the typo in the settings tab list:
replace the misspelled string "secutiry" with "security" in the exported tab
enumeration/array defined in index.ts (the array containing "account",
"secutiry", "repositories") so URL param ?settings_tab=security will match.
Ensure the corrected string is used wherever that exported list (settings tabs
enum/array) is referenced for routing or URL parsing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant